package net.entelijan.testutil;

import java.awt.Component;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;

public class CobeanTestUtil {

	private static Log log = LogFactory.getLog(CobeanTestUtil.class);

	public CobeanTestUtil() {
		super();
	}

	/**
	 * Creates a date
	 * 
	 * @param pattern
	 *            A date as used for java.text.SimpleDateFormat
	 * @param date
	 *            A string defining a date using 'pattern'
	 * @return The created date
	 */
	public static Date createDate(String pattern, String date) {
		try {
			SimpleDateFormat sdf = new SimpleDateFormat(pattern);
			return sdf.parse(date);
		} catch (ParseException e) {
			throw new IllegalArgumentException("Could not create date from '"
					+ date + "' using '" + pattern + "'");
		}
	}

	/**
	 * Sets the name of all components that are also properties to the property
	 * name. Convenient method for panels used in fest test cases, as there all
	 * the components have to have names in order to be identified by the test
	 * runner engine
	 * 
	 * @param panel
	 *            A panel containing components in propertries
	 */
	public static void setComponentNamesFromPropertyNames(Object panel) {
		BeanWrapper bw = new BeanWrapperImpl(panel);
		for (PropertyDescriptor pd : bw.getPropertyDescriptors()) {
			try {
				final Object ocomp = bw.getPropertyValue(pd.getName());
				if (ocomp instanceof Component) {
					final Component component = (Component) ocomp;
					final String oldName = component.getName();
					if (oldName != null) {
						log
								.warn("[setComponentNamesFromPropertyNames] Could not set name of component '"
										+ component.getClass().getName()
										+ "' because it was already set to '"
										+ oldName + "'");
					} else {
						component.setName(pd.getName());
						log.debug("[setComponentNamesFromPropertyNames] set '"
								+ component.getClass().getName() + "' name to "
								+ pd.getName());
					}
				}
			} catch (BeansException e) {
				// Ignore properties that cannot be read
				log
						.debug("[setComponentNamesFromPropertyNames] Could not set name of component '"
								+ pd.getName() + "' because: " + e.getMessage());
			}
		}

	}

	/**
	 * Creates a list of strings (words) from a sentance where the words are
	 * separated by spaces.
	 * 
	 * @param sentance
	 *            A senatnce
	 * @return A list of strings containing the words of the sentance
	 */
	public static List<String> createStringList(String sentance) {
		String[] sa = sentance.split(" ");
		return Arrays.asList(sa);
	}

	/**
	 * Creates a list of simple beans from a sentance. Each simple bean contains
	 * one word of the sentance.
	 * 
	 * @param sentance
	 *            A senatnce
	 * @return A list of strings containing the words of the sentance
	 */
	public static List<SimpleBean> createSimpleBeanList(String sentance) {
		String[] sa = sentance.split(" ");
		ArrayList<SimpleBean> re = new ArrayList<SimpleBean>();
		for (String word : sa) {
			re.add(new SimpleBean(word));
		}
		return re;
	}

	public static String listToString(List<?> elems) {
		StringBuilder sb = new StringBuilder();
		for (Object elem : elems) {
			sb.append("" + elem + "\n");
		}
		return sb.toString();
	}

	public static String[][] createStringArray(List<?> items,
			String... properties) {
		String[][] re = new String[items.size()][];
		for (int i = 0; i < items.size(); i++) {
			re[i] = createRowStringArray(items.get(i), properties);
		}
		return re;
	}

	private static String[] createRowStringArray(Object row, String[] properties) {
		String[] re = new String[properties.length];
		BeanWrapper bw = new BeanWrapperImpl(row);
		for (int i = 0; i < properties.length; i++) {
			re[i] = "" + bw.getPropertyValue(properties[i]);
		}
		return re;
	}

	public static void buildStringArray(StringBuilder sb, List<?> items,
			String... properties) {
		sb.append("new String[][]{\n");
		for (int i = 0; i < items.size(); i++) {
			if (i > 0) {
				sb.append(", ");
			}
			buildRowStringArray(sb, items.get(i), properties);
		}
		sb.append("}");
	}

	private static void buildRowStringArray(StringBuilder sb, Object row,
			String[] properties) {
		BeanWrapper bw = new BeanWrapperImpl(row);
		sb.append("{");
		for (int i = 0; i < properties.length; i++) {
			if (i > 0) {
				sb.append(", ");
			}
			sb.append("\"" + bw.getPropertyValue(properties[i]) + "\"");
		}
		sb.append("}\n");
	}

	/**
	 * Creates a set of testfiles and directories inside the users home
	 * directory
	 */
	public static void createTestFilesAndDirectories() {
		try {
			File homeDir = new File(System.getProperty("user.home"));
			File baseDir = createDirIfNotExists(homeDir, ".testdir");
			createFileIfNotExists(baseDir, "test00.txt");
			createFileIfNotExists(baseDir, "test01.txt");
			createFileIfNotExists(baseDir, "test02.txt");
			File dir00 = createDirIfNotExists(baseDir, "dir00");
			createFileIfNotExists(dir00, "test00.txt");
			createFileIfNotExists(dir00, "test01.txt");
			createFileIfNotExists(dir00, "test02.txt");
			File dir01 = createDirIfNotExists(baseDir, "dir01");
			createFileIfNotExists(dir01, "test00.txt");
			createFileIfNotExists(dir01, "test01.txt");
			createFileIfNotExists(dir01, "test02.txt");
		} catch (IOException e) {
			throw new IllegalStateException("Could not create testfiles. "
					+ e.getMessage(), e);
		}
	}

	private static File createDirIfNotExists(File baseDir, String dirname) {
		File newDir = new File(baseDir, dirname);
		if (!newDir.exists()) {
			if (!newDir.mkdirs()) {
				throw new IllegalStateException("Could not create " + newDir);
			}
		}
		return newDir;
	}

	private static File createFileIfNotExists(File basedir, String filename)
			throws IOException {
		File newFile = new File(basedir, filename);
		if (!newFile.exists()) {
			FileUtils
					.writeStringToFile(newFile,
							"testdata --- testdata --- testdata --- testdata --- testdata --- testdata");
		}
		return newFile;
	}
}
